home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 10 / AACD 10.iso / AACD / Games / WarpQuake / Src / snd_mem.c < prev    next >
C/C++ Source or Header  |  2000-05-22  |  7KB  |  342 lines

  1. /*
  2. Copyright (C) 1996-1997 Id Software, Inc.
  3.  
  4. This program is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU General Public License
  6. as published by the Free Software Foundation; either version 2
  7. of the License, or (at your option) any later version.
  8.  
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
  12.  
  13. See the GNU General Public License for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  18.  
  19. */
  20. // snd_mem.c: sound caching
  21.  
  22. #include "quakedef.h"
  23.  
  24. int            cache_full_cycle;
  25.  
  26. byte *S_Alloc (int size);
  27.  
  28. /*
  29. ================
  30. ResampleSfx
  31. ================
  32. */
  33. void ResampleSfx (sfx_t *sfx, int inrate, int inwidth, byte *data)
  34. {
  35.     int        outcount;
  36.     int        srcsample;
  37.     float    stepscale;
  38.     int        i;
  39.     int        sample, samplefrac, fracstep;
  40.     sfxcache_t    *sc;
  41.     
  42.     sc = Cache_Check (&sfx->cache);
  43.     if (!sc)
  44.         return;
  45.  
  46.     stepscale = (float)inrate / shm->speed;    // this is usually 0.5, 1, or 2
  47.  
  48.     outcount = sc->length / stepscale;
  49.     sc->length = outcount;
  50.     if (sc->loopstart != -1)
  51.         sc->loopstart = sc->loopstart / stepscale;
  52.  
  53.     sc->speed = shm->speed;
  54.     if (loadas8bit.value)
  55.         sc->width = 1;
  56.     else
  57.         sc->width = inwidth;
  58.     sc->stereo = 0;
  59.  
  60. // resample / decimate to the current source rate
  61.  
  62.     if (stepscale == 1 && inwidth == 1 && sc->width == 1)
  63.     {
  64. // fast special case
  65.         for (i=0 ; i<outcount ; i++)
  66.             ((signed char *)sc->data)[i]
  67.             = (int)( (unsigned char)(data[i]) - 128);
  68.     }
  69.     else
  70.     {
  71. // general case
  72.         samplefrac = 0;
  73.         fracstep = stepscale*256;
  74.         for (i=0 ; i<outcount ; i++)
  75.         {
  76.             srcsample = samplefrac >> 8;
  77.             samplefrac += fracstep;
  78.             if (inwidth == 2)
  79.                 sample = LittleShort ( ((short *)data)[srcsample] );
  80.             else
  81.                 sample = (int)( (unsigned char)(data[srcsample]) - 128) << 8;
  82.             if (sc->width == 2)
  83.                 ((short *)sc->data)[i] = sample;
  84.             else
  85.                 ((signed char *)sc->data)[i] = sample >> 8;
  86.         }
  87.     }
  88. }
  89.  
  90. //=============================================================================
  91.  
  92. /*
  93. ==============
  94. S_LoadSound
  95. ==============
  96. */
  97. sfxcache_t *S_LoadSound (sfx_t *s)
  98. {
  99.     char    namebuffer[256];
  100.     byte    *data;
  101.     wavinfo_t    info;
  102.     int        len;
  103.     float    stepscale;
  104.     sfxcache_t    *sc;
  105.     byte    stackbuf[1*1024];        // avoid dirtying the cache heap
  106.  
  107. // see if still in memory
  108.     sc = Cache_Check (&s->cache);
  109.     if (sc)
  110.         return sc;
  111.  
  112. //Con_Printf ("S_LoadSound: %x\n", (int)stackbuf);
  113. // load it in
  114.     Q_strcpy(namebuffer, "sound/");
  115.     Q_strcat(namebuffer, s->name);
  116.  
  117. //    Con_Printf ("loading %s\n",namebuffer);
  118.  
  119.     data = COM_LoadStackFile(namebuffer, stackbuf, sizeof(stackbuf));
  120.  
  121.     if (!data)
  122.     {
  123.         Con_Printf ("Couldn't load %s\n", namebuffer);
  124.         return NULL;
  125.     }
  126.  
  127.     info = GetWavinfo (s->name, data, com_filesize);
  128.     if (info.channels != 1)
  129.     {
  130.         Con_Printf ("%s is a stereo sample\n",s->name);
  131.         return NULL;
  132.     }
  133.  
  134.     stepscale = (float)info.rate / shm->speed;    
  135.     len = info.samples / stepscale;
  136.  
  137.     len = len * info.width * info.channels;
  138.  
  139.     sc = Cache_Alloc ( &s->cache, len + sizeof(sfxcache_t), s->name);
  140.     if (!sc)
  141.         return NULL;
  142.     
  143.     sc->length = info.samples;
  144.     sc->loopstart = info.loopstart;
  145.     sc->speed = info.rate;
  146.     sc->width = info.width;
  147.     sc->stereo = info.channels;
  148.  
  149.     ResampleSfx (s, sc->speed, sc->width, data + info.dataofs);
  150.  
  151.     return sc;
  152. }
  153.  
  154.  
  155.  
  156. /*
  157. ===============================================================================
  158.  
  159. WAV loading
  160.  
  161. ===============================================================================
  162. */
  163.  
  164.  
  165. byte    *data_p;
  166. byte     *iff_end;
  167. byte     *last_chunk;
  168. byte     *iff_data;
  169. int     iff_chunk_len;
  170.  
  171.  
  172. short GetLittleShort(void)
  173. {
  174.     short val = 0;
  175.     val = *data_p;
  176.     val = val + (*(data_p+1)<<8);
  177.     data_p += 2;
  178.     return val;
  179. }
  180.  
  181. int GetLittleLong(void)
  182. {
  183.     int val = 0;
  184.     val = *data_p;
  185.     val = val + (*(data_p+1)<<8);
  186.     val = val + (*(data_p+2)<<16);
  187.     val = val + (*(data_p+3)<<24);
  188.     data_p += 4;
  189.     return val;
  190. }
  191.  
  192. void FindNextChunk(char *name)
  193. {
  194.     while (1)
  195.     {
  196.         data_p=last_chunk;
  197.  
  198.         if (data_p >= iff_end)
  199.         {    // didn't find the chunk
  200.             data_p = NULL;
  201.             return;
  202.         }
  203.         
  204.         data_p += 4;
  205.         iff_chunk_len = GetLittleLong();
  206.         if (iff_chunk_len < 0)
  207.         {
  208.             data_p = NULL;
  209.             return;
  210.         }
  211. //        if (iff_chunk_len > 1024*1024)
  212. //            Sys_Error ("FindNextChunk: %i length is past the 1 meg sanity limit", iff_chunk_len);
  213.         data_p -= 8;
  214.         last_chunk = data_p + 8 + ( (iff_chunk_len + 1) & ~1 );
  215.         if (!Q_strncmp(data_p, name, 4))
  216.             return;
  217.     }
  218. }
  219.  
  220. void FindChunk(char *name)
  221. {
  222.     last_chunk = iff_data;
  223.     FindNextChunk (name);
  224. }
  225.  
  226.  
  227. void DumpChunks(void)
  228. {
  229.     char    str[5];
  230.     
  231.     str[4] = 0;
  232.     data_p=iff_data;
  233.     do
  234.     {
  235.         memcpy (str, data_p, 4);
  236.         data_p += 4;
  237.         iff_chunk_len = GetLittleLong();
  238.         Con_Printf ("0x%x : %s (%d)\n", (int)(data_p - 4), str, iff_chunk_len);
  239.         data_p += (iff_chunk_len + 1) & ~1;
  240.     } while (data_p < iff_end);
  241. }
  242.  
  243. /*
  244. ============
  245. GetWavinfo
  246. ============
  247. */
  248. wavinfo_t GetWavinfo (char *name, byte *wav, int wavlength)
  249. {
  250.     wavinfo_t    info;
  251.     int     i;
  252.     int     format;
  253.     int        samples;
  254.  
  255.     memset (&info, 0, sizeof(info));
  256.  
  257.     if (!wav)
  258.         return info;
  259.         
  260.     iff_data = wav;
  261.     iff_end = wav + wavlength;
  262.  
  263. // find "RIFF" chunk
  264.     FindChunk("RIFF");
  265.     if (!(data_p && !Q_strncmp(data_p+8, "WAVE", 4)))
  266.     {
  267.         Con_Printf("Missing RIFF/WAVE chunks\n");
  268.         return info;
  269.     }
  270.  
  271. // get "fmt " chunk
  272.     iff_data = data_p + 12;
  273. // DumpChunks ();
  274.  
  275.     FindChunk("fmt ");
  276.     if (!data_p)
  277.     {
  278.         Con_Printf("Missing fmt chunk\n");
  279.         return info;
  280.     }
  281.     data_p += 8;
  282.     format = GetLittleShort();
  283.     if (format != 1)
  284.     {
  285.         Con_Printf("Microsoft PCM format only\n");
  286.         return info;
  287.     }
  288.  
  289.     info.channels = GetLittleShort();
  290.     info.rate = GetLittleLong();
  291.     data_p += 4+2;
  292.     info.width = GetLittleShort() / 8;
  293.  
  294. // get cue chunk
  295.     FindChunk("cue ");
  296.     if (data_p)
  297.     {
  298.         data_p += 32;
  299.         info.loopstart = GetLittleLong();
  300. //        Con_Printf("loopstart=%d\n", sfx->loopstart);
  301.  
  302.     // if the next chunk is a LIST chunk, look for a cue length marker
  303.         FindNextChunk ("LIST");
  304.         if (data_p)
  305.         {
  306.             if (!strncmp (data_p + 28, "mark", 4))
  307.             {    // this is not a proper parse, but it works with cooledit...
  308.                 data_p += 24;
  309.                 i = GetLittleLong ();    // samples in loop
  310.                 info.samples = info.loopstart + i;
  311. //                Con_Printf("looped length: %i\n", i);
  312.             }
  313.         }
  314.     }
  315.     else
  316.         info.loopstart = -1;
  317.  
  318. // find data chunk
  319.     FindChunk("data");
  320.     if (!data_p)
  321.     {
  322.         Con_Printf("Missing data chunk\n");
  323.         return info;
  324.     }
  325.  
  326.     data_p += 4;
  327.     samples = GetLittleLong () / info.width;
  328.  
  329.     if (info.samples)
  330.     {
  331.         if (samples < info.samples)
  332.             Sys_Error ("Sound %s has a bad loop length", name);
  333.     }
  334.     else
  335.         info.samples = samples;
  336.  
  337.     info.dataofs = data_p - wav;
  338.     
  339.     return info;
  340. }
  341.  
  342.